package com.yjzx.util.common.util.number;

import java.util.Calendar;
import java.util.Date;

/**
 * @author guozhi
 * @date 2024/12/6
 * @description ByteUtils
 */
public class ByteUtils {

    /**
     * 从右开始的索引（从long中获取指定byte的位置）
     *
     * @param word
     * @param c
     * @return
     */
    public static long findByteIndex(long word, byte c) {
        long v1 = ((long) c << 56) | ((long) c << 48);
        long v2 = ((long) c << 40) | ((long) c << 32);
        long v3 = ((long) c << 24) | ((long) c << 16);
        long v4 = ((long) c << 8) | ((long) c);
        v1 |= v2;v3 |= v4;v1 |= v3;
        long input = word ^ v1;
        long result = (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;
        return Long.numberOfTrailingZeros(result) >>> 3;
    }

    /**
     * long转为byte数组(负数转换需要考虑是否需要同值还是同二进制码)
     *
     * @param val long值
     * @return
     */
    public static byte[] longToBytes(long val) {
        byte[] buff = new byte[8];
        buff[0] = (byte) (0xff & (val >>> 56));
        buff[1] = (byte) (0xff & (val >>> 48));
        buff[2] = (byte) (0xff & (val >>> 40));
        buff[3] = (byte) (0xff & (val >>> 32));
        buff[4] = (byte) (0xff & (val >>> 24));
        buff[5] = (byte) (0xff & (val >>> 16));
        buff[6] = (byte) (0xff & (val >>> 8));
        buff[7] = (byte) (0xff & val);
        return buff;
    }

    /**
     * int 转为byte数组(负数转换需要考虑是否需要同值还是同二进制码)
     *
     * @param val int值
     * @return
     */
    public static byte[] intToBytes(int val) {
        byte[] buff = new byte[4];
        buff[0] = (byte) (0xff & (val >>> 24));
        buff[1] = (byte) (0xff & (val >>> 16));
        buff[2] = (byte) (0xff & (val >>> 8));
        buff[3] = (byte) (0xff & val);


        return buff;
    }

    /**
     * short 转为byte数组(负数转换需要考虑是否需要同值还是同二进制码)
     *
     * @param val short值
     * @return
     */
    public static byte[] shortToBytes(short val) {
        byte[] buff = new byte[2];
        buff[0] = (byte) (0xff & (val >>> 8));
        buff[1] = (byte) (0xff & val);
        return buff;
    }

    /**
     * 数字转为字节数组
     *
     * @param val
     * @param offset
     * @return
     */
    public static byte[] numberToBytes(long val, int offset) {
        switch (offset) {
            case 4:
                return intToBytes((int) (val));
            case 8:
                return longToBytes(val);
            case 1:
                return new byte[]{(byte) (val & 0xff)};
            case 2:
                return shortToBytes((short) (val));

            default:
                byte[] buff = new byte[offset];
                for (int i = offset - 1; i >= 0; i--) {
                    buff[i] = (byte) (val & 0xff);
                    val >>>= 8;
                }
                return buff;
        }
    }


    /**
     * 从一个字节数组源中读取指定位置的指定字节数量转为int数字
     *
     * @param srcBytes 字节数组源
     * @param offset   字节数组源当前偏移值
     * @param len      指定转为数字的字节数量，不要超过4
     * @return int数
     */
    public static int bytesToInt(byte[] srcBytes, int offset, int len) {
        byte[] bytesInt = new byte[len];
        System.arraycopy(srcBytes, offset, bytesInt, 0, len);
        return bytesL4ToInt(bytesInt);
    }

    /**
     * 从一个字节数组源中读取指定位置的指定字节数量转为Long数字
     *
     * @param srcBytes 字节数组源
     * @param offset   字节数组源当前偏移值
     * @param len      指定转为数字的字节数量，不要超过8
     * @return long数
     */
    public static long bytesToLong(byte[] srcBytes, int offset, int len) {
        byte[] bytes = new byte[len];
        System.arraycopy(srcBytes, offset, bytes, 0, len);
        return bytesL8ToLong(bytes);
    }

    /**
     * 将最多4字节的byte数组转成一个int值
     *
     * @param bytes 4字节的byte数组,可小于4字节
     * @return int数
     */
    public static int bytesL4ToInt(byte[] bytes) {
        byte[] a = new byte[4];
        int i = a.length - 1;
        int j = bytes.length - 1;
        //从b的尾部(即int值的低位)开始copy数据
        for (; i >= 0; i--, j--) {
            if (j >= 0) {
                a[i] = bytes[j];
            } else {
                //如果b.length不足4,则将高位补0
                a[i] = 0;
            }
        }
        //&0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
        int v0 = (a[0] & 0xff) << 24;
        int v1 = (a[1] & 0xff) << 16;
        int v2 = (a[2] & 0xff) << 8;
        int v3 = (a[3] & 0xff);
        return v0 + v1 + v2 + v3;
    }

    /**
     * 将最多8字节的byte数组转成一个long值
     *
     * @param bytes 8字节的byte数组，可小于8字节
     * @return int数
     */
    public static long bytesL8ToLong(byte[] bytes) {
        long[] a = new long[8];
        int i = a.length - 1;
        int j = bytes.length - 1;
        for (; i >= 0; i--, j--) {//从b的尾部(即int值的低位)开始copy数据
            if (j >= 0) {
                a[i] = bytes[j];
            } else {
                a[i] = 0;//如果b.length不足8,则将高位补0
            }
        }
        //&0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
        long v0 = (a[0] & 0xff) << 56;
        long v1 = (a[1] & 0xff) << 48;
        long v2 = (a[2] & 0xff) << 40;
        long v3 = (a[3] & 0xff) << 32;
        long v4 = (a[4] & 0xff) << 24;
        long v5 = (a[5] & 0xff) << 16;
        long v6 = (a[6] & 0xff) << 8;
        long v7 = (a[7] & 0xff);
        return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
    }

    /**
     * char 字符转为byte
     *
     * @param c 字符
     * @return byte，1字节
     */
    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 比较两个字节数字是否相等
     *
     * @param bytes1 字节数组1
     * @param bytes2 字节数组2
     * @return 是否相等
     */
    public static boolean bytesEquals(byte[] bytes1, byte[] bytes2) {
        if (bytes1 == bytes2) {
            return true;
        }
        if (bytes1 == null) {
            return false;
        }
        if (bytes2 == null) {
            return false;
        }
        if (bytes1.length != bytes2.length) {
            return false;
        }
        for (int i = 0; i < bytes1.length; i++) {
            if (bytes1[i] != bytes2[i]) {
                return false;
            }
        }
        return true;
    }


    /**
     * 从参数字节数组中获取指定长度的字节数组
     *
     * @param src    字节数组
     * @param offset 偏移量
     * @param len    指定的长度
     * @return 获取到的字节数组
     */
    public static byte[] getBytesForLen(byte[] src, int offset, int len) {
        byte[] bytes = new byte[len];
        System.arraycopy(src, offset, bytes, 0, len);
        return bytes;
    }

    /**
     * 从一个字节数组源中读取指定位置的指定字节数量转为字符
     *
     * @param srcBytes 字节数组源
     * @param offset   字节数组源当前偏移值
     * @param len      指定转为数字的字节数量
     * @return int数
     */
    public static String bytesToString(byte[] srcBytes, int offset, int len) {
        byte[] bytesInt = new byte[len];
        System.arraycopy(srcBytes, offset, bytesInt, 0, len);
        return new String(bytesInt);
    }

    /**
     * 十进制string转BCD编码
     *
     * @param asc
     * @return
     */
    public static byte[] strToBcd(String asc) {
        int len = asc.length();
        int mod = len % 2;
        if (mod != 0) {
            asc = "0" + asc;
            len = asc.length();
        }
        byte abt[];
        if (len >= 2) {
            len = len / 2;
        }
        byte bbt[] = new byte[len];
        abt = asc.getBytes();
        int j, k;
        for (int p = 0; p < asc.length() / 2; p++) {
            int p1 = p << 1, p2 = p1 + 1;

            if ((abt[p1] >= '0') && (abt[p1] <= '9')) {
                j = abt[p1] - '0';
            } else if ((abt[p1] >= 'a') && (abt[p1] <= 'z')) {
                j = abt[p1] - 'a' + 0x0a;
            } else {
                j = abt[p1] - 'A' + 0x0a;
            }
            if ((abt[p2] >= '0') && (abt[p2] <= '9')) {
                k = abt[p2] - '0';
            } else if ((abt[p2] >= 'a') && (abt[p2] <= 'z')) {
                k = abt[p2] - 'a' + 0x0a;
            } else {
                k = abt[p2] - 'A' + 0x0a;
            }
            int a = (j << 4) + k;
            byte b = (byte) a;
            bbt[p] = b;
        }
        return bbt;
    }

    /**
     * 将6个字节的日期字节数组转化为date
     * 6个字节分别对应年月日时分秒，年偏移2000
     *
     * @param dateBytes 日期字节数组
     * @return 流水号字符串
     */
    public static Date bytesL6ToDate(byte[] dateBytes) {
        if (dateBytes.length != 6) {
            return null;
        }
        int offset = 0;
        //年，偏移2000
        int year = bytesToInt(dateBytes, offset++, 1) + 2000;
        //月
        int month = bytesToInt(dateBytes, offset++, 1);
        //日
        int day = bytesToInt(dateBytes, offset++, 1);
        //时
        int hour = bytesToInt(dateBytes, offset++, 1);
        //分
        int minute = bytesToInt(dateBytes, offset++, 1);
        //秒
        int second = bytesToInt(dateBytes, offset, 1);
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month - 1, day, hour, minute, second);
        return calendar.getTime();
    }
}
